package com.baijia.ticket;

import java.util.HashMap;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

import com.baijia.authentication.Authentication;
import com.baijia.authentication.principal.Service;

/**
 * @title TicketGrantingTicketImpl
 * @desc TGT会授权任何一个访问，只要该访问cookie包含TGT
 * @author caoliang
 * @date 2015年12月5日
 * @version 1.0
 */
public final class TicketGrantingTicketImpl extends AbstractTicket implements TicketGrantingTicket {

    private static final long serialVersionUID = -5197946718924166491L;

    private static final Logger logger = LoggerFactory.getLogger(TicketGrantingTicketImpl.class);

    // TGT过期时间
    private static final int EXPIRE_TIME = 60 * 60 * 49;

    private static final int REMEMBER_ME_EXPIRE_TIME = 60 * 60 * 24 * 30;

    private Authentication authentication;

    private final HashMap<String, Service> services = new HashMap<String, Service>();

    public TicketGrantingTicketImpl() {
        // nothing to do
    }

    public TicketGrantingTicketImpl(final String id, final TicketGrantingTicketImpl ticketGrantingTicket,
        final Authentication authentication) {
        super(id, ticketGrantingTicket);

        Assert.notNull(authentication, "authentication cannot be null");

        this.authentication = authentication;
    }

    public TicketGrantingTicketImpl(final String id, final Authentication authentication) {
        this(id, null, authentication);
    }

    @Override
    public Authentication getAuthentication() {
        return this.authentication;
    }

    @Override
    public synchronized ServiceTicket grantServiceTicket(final String id, final Service service,
        final boolean credentialsProvided) {

        final ServiceTicket serviceTicket =
            new ServiceTicketImpl(id, this, service, this.getCountOfUses() == 0 || credentialsProvided);

        updateState();

        service.setPrincipal(authentication.getPrincipal());
        // 每次授权ST，map新增，更新redis中存储tgt，以便登出使用
        this.services.put(id, service);

        return serviceTicket;
    }

    private void logOutOfServices() {
        for (final Entry<String, Service> entry : this.services.entrySet()) {

            if (!entry.getValue().logOutOfService(entry.getKey())) {
                logger.debug("Logout message not sent to [" + entry.getValue().getId() + "]; Continuing processing...");
            }
        }
    }

    @Override
    public boolean isRoot() {
        return this.getGrantingTicket() == null;
    }

    @Override
    public synchronized void expire() {
        logOutOfServices();
    }

    @Override
    public final boolean equals(final Object object) {
        if (object == null || !(object instanceof TicketGrantingTicket)) {
            return false;
        }

        final Ticket ticket = (Ticket) object;

        return ticket.getId().equals(this.getId());
    }

    @Override
    public int getExpireTime() {
        return EXPIRE_TIME;
    }

    @Override
    public int getRememberMeExpireTimeExpireTime() {
        return REMEMBER_ME_EXPIRE_TIME;
    }
}
